package com.hitqz.robot.biz.controller;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hitqz.robot.api.business.dto.SubscriptTopicDto;
import com.hitqz.robot.api.business.entity.JobCachesEntity;
import com.hitqz.robot.api.business.vo.JobCachesVo;
import com.hitqz.robot.biz.service.JobCachesService;
import com.hitqz.robot.common.core.util.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.List;

/**
 * @author xupkun
 * @date 2025/1/13
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/jobCaches")
@Tag(name = "缓存任务管理")
@Slf4j
public class JobCachesController {

    private final JobCachesService jobCachesService;

    private static final String EVENT_NAME = "job_caches\n";
    private static final Duration INTERVAL_DURATION = Duration.ofSeconds(1);
    private static final Duration TIMEOUT_DURATION = Duration.ofSeconds(5);


    @DeleteMapping("/delete/{id}")
    @Operation(summary = "删除单条任务---分组")
    public R deleteJob(@PathVariable Integer id) {
        //jobCachesService.removeById(id);
        List<JobCachesVo> jobCachesVos = Lists.newArrayList();
        List<JobCachesEntity> list = jobCachesService.list(Wrappers.<JobCachesEntity>lambdaQuery()
                .orderByAsc(JobCachesEntity::getSn));
        String lastName = "";
        Integer lastIndex = -1;
        List<Integer> removeIds = Lists.newArrayList();
        for (JobCachesEntity jobCachesEntity: list) {
            if (!lastName.equals(jobCachesEntity.getTaskName())) {
                // 新记录
                lastIndex ++;
                JobCachesVo vo = new JobCachesVo();
                vo.setTaskName(jobCachesEntity.getTaskName());
                vo.setNumber(1);
                vo.setId(lastIndex +1);
                jobCachesVos.add(lastIndex, vo);
                lastName = vo.getTaskName();
                if (vo.getId().equals(id)) {
                    removeIds.add(jobCachesEntity.getId());
                }
            } else {
                // 旧记录
                JobCachesVo vo = jobCachesVos.get(lastIndex);
                vo.setNumber(vo.getNumber() + 1);
                lastName = vo.getTaskName();
                if (vo.getId().equals(id)) {
                    removeIds.add(jobCachesEntity.getId());
                }
            }
        }
        jobCachesService.removeByIds(removeIds);
        SpringUtil.getApplicationContext().publishEvent(new SubscriptTopicDto("jobCaches"));

        return R.ok();
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除全部任务")
    public R delete() {
        jobCachesService.remove(null);
        SpringUtil.getApplicationContext().publishEvent(new SubscriptTopicDto("jobCaches"));
        return R.ok();
    }

    @GetMapping("/topUp")
    @Operation(summary = "置顶任务组模块")
    public R topUp(@RequestParam Integer id) {
        List<JobCachesVo> jobCachesVos = Lists.newArrayList();
        List<JobCachesEntity> list = jobCachesService.list(Wrappers.<JobCachesEntity>lambdaQuery()
                .orderByAsc(JobCachesEntity::getSn));
        String lastName = "";
        if (id ==1) {
            return R.ok();
        }
        Integer lastIndex = -1;
        List<JobCachesEntity> removeIds = Lists.newArrayList();
        List<JobCachesEntity> otherIds = Lists.newArrayList();
        for (JobCachesEntity jobCachesEntity: list) {
            if (!lastName.equals(jobCachesEntity.getTaskName())) {
                // 新记录
                lastIndex ++;
                JobCachesVo vo = new JobCachesVo();
                vo.setTaskName(jobCachesEntity.getTaskName());
                vo.setNumber(1);
                vo.setId(lastIndex +1);
                jobCachesVos.add(lastIndex, vo);
                lastName = vo.getTaskName();
                if (vo.getId().equals(id)) {
                    removeIds.add(jobCachesEntity);
                } else {
                    otherIds.add(jobCachesEntity);
                }
            } else {
                // 旧记录
                JobCachesVo vo = jobCachesVos.get(lastIndex);
                vo.setNumber(vo.getNumber() + 1);
                lastName = vo.getTaskName();
                if (vo.getId().equals(id)) {
                    removeIds.add(jobCachesEntity);
                } else {
                    otherIds.add(jobCachesEntity);
                }
            }
        }
        // 批量修改序号
        int index = 0;
        // 更新置顶的
        for (JobCachesEntity jobCachesEntity: removeIds) {
            jobCachesEntity.setSn(index);
            jobCachesService.updateById(jobCachesEntity);
            index++;
        }
        // 更新其他的。
        for (JobCachesEntity jobCachesEntity: otherIds) {
            jobCachesEntity.setSn(index);
            jobCachesService.updateById(jobCachesEntity);
            index++;
        }

       SpringUtil.getApplicationContext().publishEvent(new SubscriptTopicDto("jobCaches"));
       return R.ok();
    }



    @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @Operation(summary = "缓存任务数据",description = "客户端采用EventSource进行连接")
    public Flux<ServerSentEvent<R<List<JobCachesVo>>>> recentTickets() {
        return Flux.interval(INTERVAL_DURATION)
                .flatMap(sequence -> buildServerSentEvent(sequence), 1)
                .doOnCancel(() -> log.info("Subscription cancelled"))
                .doOnError(error -> log.error("Error in recentTickets: {}", error.getMessage()))
                .doOnSubscribe(subscription -> log.info("Subscription started"));
    }

    private Mono<ServerSentEvent<R<List<JobCachesVo>>>> buildServerSentEvent(long sequence) {
        return Mono.fromCallable(() -> jobCachesService.sortType())
                .map(tickets -> createEvent(sequence, tickets))
                .onErrorResume(e -> {
                    log.error("Error fetching recent tickets: {}", e.getMessage());
                    return Mono.just(createEmptyEvent(sequence));
                })
                .timeout(TIMEOUT_DURATION, Mono.just(createEmptyEvent(sequence)));
    }

    private ServerSentEvent<R<List<JobCachesVo>>> createEvent(long sequence, List<JobCachesVo> tickets) {
        return ServerSentEvent.<R<List<JobCachesVo>>>builder()
                .id(String.valueOf(sequence))
                .event(EVENT_NAME)
                .data(R.ok(tickets))
                .build();
    }

    private ServerSentEvent<R<List<JobCachesVo>>> createEmptyEvent(long sequence) {
        return ServerSentEvent.<R<List<JobCachesVo>>>builder()
                .id(String.valueOf(sequence))
                .event(EVENT_NAME)
                .data(R.ok(List.of()))
                .build();
    }


}
